﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;

namespace Simple.Common.Helpers
{
    public static class ExpressionHelper
    {
        private class RebindParameterVisitor : ExpressionVisitor
        {
            private readonly ParameterExpression _oldParameter;

            private readonly ParameterExpression _newParameter;

            public RebindParameterVisitor(ParameterExpression oldParameter, ParameterExpression newParameter)
            {
                _oldParameter = oldParameter;
                _newParameter = newParameter;
            }

            protected override Expression VisitParameter(ParameterExpression node)
            {
                if (node != _oldParameter)
                {
                    return base.VisitParameter(node);
                }

                return _newParameter;
            }
        }
        public static Expression<Func<T, bool>> ConcatOr<T>(this IEnumerable<Expression<Func<T, bool>>> expressions)
        {
            var conditions = expressions?.ToList();
            if (conditions == null || conditions.Count == 0)
            {
                throw new ArgumentNullException(nameof(expressions));
            }

            if (conditions.Count == 1)
            {
                return conditions.First();
            }

            Expression<Func<T, bool>> current = null;
            foreach (var condition in conditions)
            {
                current = current == null
                    ? condition
                    : current.Or(condition);
            }

            return current;
        }

        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2)
        {
            Expression right = new RebindParameterVisitor(expr2.Parameters[0], expr1.Parameters[0]).Visit(expr2.Body);
            return Expression.Lambda<Func<T, bool>>(Expression.OrElse(expr1.Body, right), expr1.Parameters);
        }
    }
}
